<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Widget Test Suite</title>

    <script src="../../../build/yui/yui.js"></script>

    <style type="text/css">
        #console .yui3-console-entry {
            padding:2px;
            margin:0px;
            min-height:0;
        }

        #console .yui3-console-entry-fail .yui3-console-entry-cat {
            background-color:red;
        }

        #console .yui3-console-entry-pass .yui3-console-entry-cat {
            background-color:green;
        }

        #console .yui3-console-entry-perf .yui3-console-entry-cat {
            background-color:blue;
        }

        #console {
            position:static;
        }

        html, body {
            height:100%;
        }
    </style>
</head>
<body class="yui3-skin-sam">
<div id="testbed" class="yui3-skin-foo"></div>
<script>
YUI({useBrowserConsole:false}).use('test', 'widget', 'node-event-simulate', 'console', function (Y) {

    var suite = new Y.Test.Suite("Widget Tests");

    suite.add(new Y.Test.Case({

        name : "getSkinName",
    
        "getSkinName should return null if not rendered" : function () {
            var w = new Y.Widget();
    
            Y.Assert.isNull( w.getSkinName() );
        },

        "getSkinName should return name from BB if available": function () {
            var bb = Y.Node.create( '<div class="yui3-skin-foo"><div></div></div>' ),
                cb = bb.one( 'div' ),
                w = new Y.Widget( {
                boundingBox: bb,
                contentBox:  cb
            } );
    
            Y.Assert.areEqual( "foo", w.getSkinName() );
        },
    
        "getSkinName should return name from body or null": function () {
            var w = new Y.Widget().render(),
                body = Y.one( 'body' );
    
            Y.Assert.areEqual( "sam", w.getSkinName() );
    
            body.removeClass( "yui3-skin-sam" );
    
            Y.Assert.isNull( w.getSkinName() );
    
            body.addClass( "yui3-skin-sam" );
        },
    
        "getSkinName should return name from ancestor if both ancestor and body are classed": function () {
            var w = new Y.Widget().render( '#testbed' ),
                body = Y.one( 'body' );
    
            body.addClass( "yui3-skin-sam" );
    
            Y.Assert.areEqual( "foo", w.getSkinName() );
        }
    }));

    suite.add(new Y.Test.Case({

        name:"destroy",
    
        testRenderedDestroy: function() {
            var w = new Y.Widget({id:"foo"}).render();
            try {
                w.destroy();
                Y.Assert.isNull(Y.Node.one("#foo"), "Bounding box still in DOM");
            } catch(e) {
                Y.Assert.fail("w.destroy() on a rendered widget threw an exception" + e);
            }
        },
        
        testRenderedDeepDestroy: function() {
            var w = new Y.Widget({id:"foo"}).render();
            var nref = Y.Node.create('<div id="deep">Foo</div>');

            w.get("contentBox").appendChild(nref);

            try {
                w.destroy(true);

                Y.Assert.isNull(Y.Node.one("#foo"), "Bounding box still in DOM");
                Y.Assert.isNull(Y.Node.one("#deep"), "Deep content box still in DOM");
                Y.Assert.isNull(Y.Node.getDOMNode(nref), "Deep content still in Node cache");

            } catch(e) {
                Y.Assert.fail("w.destroy(true) on a rendered widget threw an exception" + e);
            }
        },
    
        testUnrenderedDestroy: function() {
            var w = new Y.Widget();
            try {
                w.destroy();
            } catch(e) {
                Y.Assert.fail("w.destroy() on an unrendered widget threw an exception" + e);
            }
        },
        
        testSingleBoxDestroy: function() {

            function MyWidget() {
                MyWidget.superclass.constructor.apply(this, arguments);
            };
            MyWidget.NAME = "myWidget";

            Y.extend(MyWidget, Y.Widget, {
                CONTENT_TEMPLATE:null
            });

            var w = new MyWidget({
                id:"foo"
            });
            w.render();

            try {
                w.destroy();
                Y.Assert.isNull(Y.Node.one("#foo"), "Bounding box still in DOM");
            } catch(e) {
                Y.Assert.fail("w.destroy() on a single box widget threw an exception" + e);
            }
        },

        testSingleBoxDeepDestroy: function() {

            function MyWidget() {
                MyWidget.superclass.constructor.apply(this, arguments);
            };
            MyWidget.NAME = "myWidget";

            Y.extend(MyWidget, Y.Widget, {
                CONTENT_TEMPLATE:null
            });

            var w = new MyWidget({
                id:"foo"
            });
            w.render();

            var nref = Y.Node.create('<div id="deep_single">Foo</div>');
            w.get("contentBox").appendChild(nref);

            try {
                w.destroy(true);
                Y.Assert.isNull(Y.Node.one("#foo"), "Bounding box still in DOM");
                Y.Assert.isNull(Y.Node.one("#deep_single"), "Deep content box still in DOM");
                Y.Assert.isNull(Y.Node.getDOMNode(nref), "Deep content still in Node cache");
            } catch(e) {
                Y.Assert.fail("w.destroy(true) on a single box widget threw an exception" + e);
            }
        }        
    }));

    suite.add(new Y.Test.Case({

        name:"UI Events",

        testSingleSimple: function() {

            var w, h, cb,
                actualEvents = [],
                expectedEvents = ["widget:click"];

            w = new Y.Widget();
            cb = w.get("contentBox");

            cb.append("<p class='et'>Some Content For My Widget</p>");

            h = function(e) { actualEvents.push(e.type); };

            w.on("click", h);
            w.render();

            cb.one(".et").simulate("click");

            Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);

            w.destroy();
        },

        testSingleComplex: function() {

            var w, h, cb
                actualEvents = [],
                expectedEvents = ["widget:render",
                                  "widget:renderedChange",
                                  "widget:render",
                                  "widget:mousedown", 
                                  "widget:mouseup",
                                  "widget:mouseup",
                                  "widget:mouseup",
                                  "widget:mouseup",
                                  "widget:mouseup",
                                  "widget:mouseup",
                                  "widget:click"];

            w = new Y.Widget();
            cb = w.get("contentBox");

            cb.append("<p class='et'>Some Content For My Widget</p>");

            h = function(e) { actualEvents.push(e.type); };

            w.on({
                "click": h,
                "render": h,
                "renderedChange": h
            });

            w.on("widget:mouseup", h);
            w.on("foo|widget:mouseup", h);
            w.on("mouseup", h);

            w.after("widget:mouseup", h);
            w.after("foo|widget:mouseup", h);
            w.after("mouseup", h);

            w.after({
                "mousedown" : h,
                "render" : h
            });

            w.render();
            
            cb.one(".et").simulate("mousedown");
            cb.one(".et").simulate("mouseup");            
            cb.one(".et").simulate("click");

            Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);

            w.destroy();
        },

        testNested: function() {

            var outer = new Y.Widget();
            var inner = new Y.Widget();
            var ocb = outer.get('contentBox');
            var icb = inner.get('contentBox');

            var expectedEvents = ["outerClick", "innerClick", "outerClick"];
            var actualEvents = [];

            outer.render();
            ocb.setContent("<span class='oet'>Outer Content</span>");

            inner.render(ocb);
            icb.setContent("<span class='iet'>Inner Content</span>");

            inner.after('click', function() {actualEvents.push("innerClick");});
            outer.after('click', function() {actualEvents.push("outerClick");});

            // Only outer
            ocb.one(".oet").simulate("click");

            // One Inner, One Outer
            ocb.one(".iet").simulate("click");

            Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
            
            outer.destroy();
            inner.destroy();
        },

        testMultipleInstances : function() {

            var actualEvents = [],
                expectedEvents = ["clickOuter", "clickInner", "clickOuter"],
                w1,
                w2;

            YUI().use('widget', function (Y) {

                w1 = new Y.Widget({render:true});
                w1.get('contentBox').append('<div class="w2-container"></div><span class="miouter">Outer</span>');

                w1.on('click', function (e) {
                    actualEvents.push("clickOuter");
                });

                YUI().use('widget', function (Y1) {

                    w2 = new Y1.Widget({render:".w2-container"});
                    w2.get('contentBox').append('<span class="miinner">Inner</span>');

                    w2.on('click', function (e) {
                        actualEvents.push("clickInner");
                    });
                });
            });

            Y.Node.one(".miouter").simulate("click"); // only outer, once.
            Y.Node.one(".miinner").simulate("click"); // inner, bubbled to outer (once each, without JS errors)
            
            Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);

            w1.destroy();
            w2.destroy();
        }
    }));

    suite.add(new Y.Test.Case({

        name:"clone",
        
        testWidgetClone : function() {
            var a = new Y.Widget();
            var b = new Y.Widget();
            var c = new Y.Widget();
    
            var a1 = Y.clone(a);
            var a2 = Y.clone(a1);
            var a3 = Y.clone(a2);
    
            Y.Assert.isTrue(a instanceof Y.Widget);
            Y.Assert.isTrue(a1 instanceof Y.Widget);
            Y.Assert.isTrue(a2 instanceof Y.Widget);
            Y.Assert.isTrue(a3 instanceof Y.Widget);
    
            var b1 = Y.clone(b);
            var b2 = Y.clone(b1);
            var b3 = Y.clone(b2);
    
            Y.Assert.isTrue(b instanceof Y.Widget);
            Y.Assert.isTrue(b1 instanceof Y.Widget);
            Y.Assert.isTrue(b2 instanceof Y.Widget);
            Y.Assert.isTrue(b3 instanceof Y.Widget);
    
            var c1 = Y.clone(c);
            var c2 = Y.clone(c1);
            var c3 = Y.clone(c2);
    
            Y.Assert.isTrue(c instanceof Y.Widget);
            Y.Assert.isTrue(c1 instanceof Y.Widget);
            Y.Assert.isTrue(c2 instanceof Y.Widget);
            Y.Assert.isTrue(c3 instanceof Y.Widget);
        },
    
        testWidgetHashClone : function() {

            // When Widget's are properties of an object it seems to break apart
            // something not passed to the recursive call maybe?
    
            var a = new Y.Widget();
            var b = new Y.Widget();
            var c = new Y.Widget();
    
            var o = {
                a : a,
                b : b,
                c : c
            };
    
            var o1 = Y.clone(o);
            var o2 = Y.clone(o1);
            var o3 = Y.clone(o2);
    
            Y.Assert.isTrue(o3.a instanceof Y.Widget);
            Y.Assert.isTrue(o3.b instanceof Y.Widget);
            Y.Assert.isTrue(o3.c instanceof Y.Widget);
        },
    
        testBaseClone : function() {
            var a = new Y.Base();
            var b = new Y.Base();
            var c = new Y.Base();
    
            // Base works fine
    
            var a1 = Y.clone(a);
            var a2 = Y.clone(a1);
            var a3 = Y.clone(a2);
    
            Y.Assert.isTrue(a instanceof Y.Base);
            Y.Assert.isTrue(a1 instanceof Y.Base);
            Y.Assert.isTrue(a2 instanceof Y.Base);
            Y.Assert.isTrue(a3 instanceof Y.Base);
    
            var b1 = Y.clone(b);
            var b2 = Y.clone(b1);
            var b3 = Y.clone(b2);
    
            Y.Assert.isTrue(b instanceof Y.Base);
            Y.Assert.isTrue(b1 instanceof Y.Base);
            Y.Assert.isTrue(b2 instanceof Y.Base);
            Y.Assert.isTrue(b3 instanceof Y.Base);
    
            var c1 = Y.clone(c);
            var c2 = Y.clone(c1);
            var c3 = Y.clone(c2);
    
            Y.Assert.isTrue(c instanceof Y.Base);
            Y.Assert.isTrue(c1 instanceof Y.Base);
            Y.Assert.isTrue(c2 instanceof Y.Base);
            Y.Assert.isTrue(c3 instanceof Y.Base);
        },
    
        testBaseHashClone : function() {
            var a = new Y.Base();
            var b = new Y.Base();
            var c = new Y.Base();
    
            var o = {
                a : a,
                b : b,
                c : c
            };
    
            var o1 = Y.clone(o);
            var o2 = Y.clone(o1);
            var o3 = Y.clone(o2);
    
            Y.Assert.isTrue(o3.a instanceof Y.Base);
            Y.Assert.isTrue(o3.b instanceof Y.Base);
            Y.Assert.isTrue(o3.c instanceof Y.Base);
        }
    }));

    Y.Test.Runner.setName("Widget Tests");
    Y.Test.Runner.add(suite);
    Y.Test.Runner.disableLogging();
    Y.Test.Runner.run();

    var console;

    Y.one("#btnRun").set("disabled", false).on("click", function() {
        if (!console) {
            console = new Y.Console({
                id:"console",
                width:"100%",
                height:"90%",
                verbose : false,
                printTimeout: 0,
                newestOnTop : false,
                entryTemplate: '<pre class="{entry_class} {cat_class} {src_class}">'+
                        '<span class="{entry_cat_class}">{label}</span>'+
                        '<span class="{entry_content_class}">{message}</span>'+
                '</pre>'
            }).render();
        }

        Y.Test.Runner.enableLogging();
        Y.Test.Runner.run();
    });
});
</script>
<p><input type="button" value="Run Tests" id="btnRun" disabled=true></p>
</body>
</html>
